public class Fisica extends Camada implements ICamada {

    private IFisica gAlgoritimo; // Implementação do algoritimo de codificação
    protected IMeioDeTransmissao gMeioDeTransmissao; // Objeto da camada
						     // transmissora para
						     // verificar se esta
						     // transmitindo ou não
    protected Thread gThreadDeRecepcao; // Trread para ativar o envio da
					// mensagem após a recepção
    protected Thread gThreadDeEnvio; // Thread para envio da mensagem;
    protected boolean gAtivoRecebimento = true; // flag para ativar ou desativar
						// a thread de recepção
    protected boolean gAtivoEnvio = true; // floag para ativar ou desativar a
					  // thread de Envio
    protected String gBuffBitsRecebidos = null; // Buff de mensagem Recebida
    protected String gBuffBitsEnvio = null; // Buff de mensagem Enviadas
    protected boolean gBuffCheio = false;

    public Fisica(
	    final ConfiguracaoDoHost.TipoCodificacaoFisica pTipoCodificacao,
	    final IMeioDeTransmissao pMeioDeTransmissao) {
	this.gMeioDeTransmissao = pMeioDeTransmissao; //Guarda a instancia do meio transmissor
	this.gThreadDeRecepcao = new Thread(runRecepcao()); //Criar a Thread de Envio
	this.gThreadDeEnvio = new Thread(runEnvio()); //Cria a thread de recepção

	//A cria o tivpo de codificação
	if (pTipoCodificacao == ConfiguracaoDoHost.TipoCodificacaoFisica.MACHESTER_DIFERENCIAL)
	    this.gAlgoritimo = new CodificacaoManchesterDiferencial();
	else if (pTipoCodificacao == ConfiguracaoDoHost.TipoCodificacaoFisica.MANCHESTER)
	    this.gAlgoritimo = new CodificacaoManchester();
    }

    @Override
    public void envia(final String pMensagem) {
	this.gBuffCheio = true;
	try {
	    this.gBuffBitsEnvio = this.gAlgoritimo
		    .codificaMensagemDeBits(pMensagem);
	} finally {
	    this.gBuffCheio = false;
	}

    }

    //Funcionamento da Thread de Envio, esse metodo vai enviar bit por bit da mensagem
    private Runnable runEnvio() {
	return new Runnable() {

	    @Override
	    public void run() {
		while (Fisica.this.gAtivoEnvio) { // Se a thread esta ativa faça
		    if (Fisica.this.isBuffEnvioCheio()) {// so vai enviar se o
							 // buff de envio
							 // eestiver cheio, ou
							 // seja se estiver
							 // mensagem para enviar
			for (char bit : Fisica.this.gBuffBitsEnvio
				.toCharArray()) { // faço um faço em cada
						  // posicação do string
			    Fisica.this.gMeioDeTransmissao.EnviarBit(String
				    .valueOf(bit)); // vou enviando char por
						    // char

			    // Congelo o envio por 10 milisegundos so para da um
			    // tempo para respirar ahsuahsa
			    try {
				Fisica.this.gThreadDeEnvio.sleep(10);
			    } catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			    }
			}
			Fisica.this.gBuffBitsEnvio = null;
		    }
		}
	    }
	};
    }

    @Override
    public void recebe(final String pMensagem) {
	String vMensagemDecodificada = this.gAlgoritimo
		.decodificaMensagemDeBits(pMensagem);
	getCamadaSuperior().recebe(vMensagemDecodificada);
    }

    //funcionamento da thread de recepção, esse metodo vai receber bit por bit ate o fim da transmissão
    private Runnable runRecepcao() {
	return new Runnable() {

	    @Override
	    public void run() {
		while (Fisica.this.gAtivoRecebimento) {
		    if (!Fisica.this.gMeioDeTransmissao.isEstaTrasmitindo()
			    && isBuffRecepcaoCheio()) {
			recebe(Fisica.this.gBuffBitsRecebidos);
			Fisica.this.gBuffBitsRecebidos = null;
		    }
		}
	    }
	};
    }

    //Metodo para verificar se o buff de recepção esta cheio
    protected boolean isBuffRecepcaoCheio() {
	return (this.gBuffBitsRecebidos != null);
    }

    //Metodo para verificar se o buff de envio esta cheio
    protected boolean isBuffEnvioCheio() {
	return (this.gBuffBitsEnvio != null);
    }

    //Metodo para receber o bit direto do meio transmissor
    public void enviaBitParaCamadaFisica(final String pBit) {
	this.gBuffBitsRecebidos = this.gBuffBitsRecebidos + pBit;
    }

    //Metodo para verificação  se o buff geral dos quadros esta cheio
    @Override
    public boolean isBuffCheio() {
	return this.gBuffCheio;
    }

    //Interface para  descrever os metodos de codificação para camada fisica
    private interface IFisica {
	//Metodo de codificação
	public String codificaMensagemDeBits(final String pMensagem);

	//Metodo para decodificação
	public String decodificaMensagemDeBits(final String pMensagem);
    }

    //Implementação da codificação e decodificação Manchester Diferencial
    private class CodificacaoManchesterDiferencial implements IFisica {

	public CodificacaoManchesterDiferencial() {
	}

	@Override
	public String codificaMensagemDeBits(final String pMensagem) {
	    return null;
	}

	@Override
	public String decodificaMensagemDeBits(final String pMensagem) {
	    return null;
	}

    }
    
    //Implementação da codificação e decodificação Manchester
    private class CodificacaoManchester implements IFisica {

	public CodificacaoManchester() {
	}

	@Override
	public String codificaMensagemDeBits(final String pMensagem) {
	    return null;
	}

	@Override
	public String decodificaMensagemDeBits(final String pMensagem) {
	    return null;
	}

    }

}
